Skip to content

fix(tests): make 3 CI-only-failing tests hermetic (closes #74)#75

Merged
itlackey merged 4 commits into
mainfrom
fix/0.8.0-ci-only-tests
Jun 4, 2026
Merged

fix(tests): make 3 CI-only-failing tests hermetic (closes #74)#75
itlackey merged 4 commits into
mainfrom
fix/0.8.0-ci-only-tests

Conversation

@itlackey

@itlackey itlackey commented Jun 4, 2026

Copy link
Copy Markdown
Owner

Makes the 3 tests that passed locally but failed on clean CI hermetic. Closes #74.

opencode-plugin.test.ts (2 tests) — commit e3ecc99

  • Set AKM_OPENCODE_IGNORE_BUNDLED_CLI=1 so the real bundled akm-cli can't preempt the candidate under test.
  • Sandbox HOME to a temp dir + create the probed fallback file there (real existsSync in probeCommand made these env-dependent).
  • Key fix: mock node:os homedir() to honor the current process.env.HOME — Bun/Node snapshot HOME at startup, so a HOME env change alone didn't move os.homedir() (which getPathAkmCandidates uses). This is why they passed on dev boxes (real ~/.local/bin/akm) and failed on clean CI.

claude-plugin.test.ts (1 test) — commit fadad21

  • Root cause was NOT bundled preemption (the Claude hook resolves akm via AKM_LOCAL_BUILD_CLI or PATH only). The test's fake akm shelled out to a bare node for config set; CI runs under Bun with no Node on PATH, so the config write failed and assertions saw {}.
  • Pin the fake helper to process.execPath (the Bun running the suite), which is guaranteed present. Bun runs .cjs natively.

Local gate green: integration 324/0, evals exit 0. Data safety: all writes under mkdtemp temp dirs, cleaned up; nothing touches real $HOME.

🤖 Generated with Claude Code

itlackey and others added 4 commits June 3, 2026 22:18
… clean CI

The two "akm CLI availability" fallback tests passed on dev machines but
failed on clean CI because they depended on machine state:

1. Bundled-CLI preemption: akm 0.8.0 added bundled akm-cli resolution
   (getResolvedAkmDetails/getBundledAkmCommand) tried before PATH/fallbacks.
   The real bundled opencode/node_modules/akm-cli/dist/cli.js exists on CI and
   was probed/selected, shadowing the candidate each test asserts on. Both
   tests now set AKM_OPENCODE_IGNORE_BUNDLED_CLI=1 (the existing default-off
   opt-out) so the bundled candidate is skipped.

2. Hidden filesystem dependency: probeCommand() does a real existsSync() on
   absolute candidate paths even when execFileSync is mocked. The fallback test
   never created ~/.local/bin/akm and never sandboxed HOME, so on clean CI the
   candidate was skipped. It now sandboxes HOME to a mkdtemp dir and creates
   $HOME/.local/bin/akm with a shebang so existsSync passes deterministically.

3. os.homedir() snapshot: getPathAkmCandidates() builds the user-local fallback
   from os.homedir(), which snapshots HOME at startup and ignores a later
   process.env.HOME change. A node:os module mock now delegates to the real os
   but makes homedir() honor the current process.env.HOME, so the HOME sandbox
   actually redirects the probed path into the temp dir (never the real
   ~/.local/bin/akm). All writes stay inside the mkdtemp sandbox.

The fallback test's mock also returns an out-of-range semver for any non-target
--version probe, defeating both the execFileSync shim's "synthesize 0.8.9"
behavior and a stale resolvedAkmCommand left cached by a prior test.

Assertions unchanged; full file 158/158 passes, including under a simulated
clean-CI env (empty HOME, no akm on PATH, bundled cli.js present).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The "session-start injects hints and curated context" test wrote its fake
`akm config set` helper to be run by a bare `node` resolved from the hook's
PATH (`${binDir}:/usr/bin:/bin`). That only works on hosts that ship
`/usr/bin/node` (most dev boxes). On clean CI the suite runs under Bun with
no Node on PATH, so the helper exited non-zero, `akm config set` failed, the
config file stayed `{}`, and the `config.defaults.agent` /
`config.profiles.agent.claude` assertions failed.

Pin the fake helper to the test suite's own interpreter (process.execPath,
i.e. the Bun running `bun test`) instead of a bare `node`. Bun runs `.cjs`
CommonJS modules natively, so the config write now succeeds regardless of
whether Node is installed.

Note: the Claude SessionStart hook (claude/hooks/akm-hook.ts) resolves akm
via AKM_LOCAL_BUILD_CLI then PATH `akm` only — it has NO bundled-akm-cli
node_modules resolution, so the bundled-CLI hypothesis did not apply here.
The real environment dependency was Node availability for the test's fake.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…he between tests

The 'prefers ~/.config/opencode/.bin/akm' test still failed on clean CI:
- getPathAkmCandidates used bare os.homedir() (snapshots HOME at process start,
  ignores later changes) for the ~/.local/bin fallback, so it probed the real CI
  home instead of the test's sandbox HOME. Now uses process.env.HOME || os.homedir(),
  matching getConfigNodeModulesAkmCommand (standard POSIX, sandboxable).
- resolveAkmCommand caches the resolved command at module level and short-circuits
  on a still-valid cached command, making resolution tests order-dependent. Add
  __resetResolvedAkmForTests() and call it in the suite beforeEach so each test
  resolves fresh under its own sandboxed env.

Local gate green: integration 324/0, evals exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
getConfigNodeModulesAkmCommand reads XDG_CONFIG_HOME || $HOME/.config, but the
test wrote its config bin under $HOME/.config directly. On CI XDG_CONFIG_HOME is
set elsewhere, so the resolver probed the wrong dir and never found the config
candidate (passed locally only because XDG_CONFIG_HOME was unset). Pin
XDG_CONFIG_HOME to the sandbox and write the bin there. Verified robust by
running with a bogus preset XDG_CONFIG_HOME (reproduces the CI condition).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Eval diff

  • Baseline SHA: f5424051799b4e4e2660c511cbbbdc82e42a25a3
  • Candidate SHA: cc4ffc3aadc592f8673b386e647762f07b173d9e

Metric deltas

Metric Key Baseline Candidate Δ Δ% Status
curation mean_expected_coverage 0.9125 0.9125 0 0.00% • unchanged
curation mean_reciprocal_rank 0.9208 0.9208 0 0.00% • unchanged
curation zero_hit_rate 0.0500 0.0500 0 0.00% • unchanged
context_budget claude_violations 0 0 0 0.00% • unchanged
context_budget opencode_violations 0 0 0 0.00% • unchanged
context_budget claude_drop_rate 0 0 0 0.00% • unchanged
context_budget opencode_drop_rate 0 0 0 0.00% • unchanged
feedback claude_precision 1 1 0 0.00% • unchanged
feedback claude_recall 1 1 0 0.00% • unchanged
feedback claude_polarity_flips 0 0 0 0.00% • unchanged
feedback opencode_precision 1 1 0 0.00% • unchanged
feedback opencode_recall 1 1 0 0.00% • unchanged
feedback opencode_polarity_flips 0 0 0 0.00% • unchanged
memory claude_avg_body_chars 1278 1194 -84 -6.57% • unchanged
memory claude_name_format_violations 0 0 0 0.00% • unchanged
memory claude_secret_leakages 0 0 0 0.00% • unchanged

Plugin surface

No surface changes.

No regressions.

@itlackey itlackey merged commit ff8b131 into main Jun 4, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 tests pass locally but fail on clean CI (bundled-CLI preemption + filesystem deps) — blocks 0.8.0 plugin release

1 participant